﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// HoughTransform - use this to find any lines or circles...
    /// </summary>
    public class HoughTransform2 : BaseImageFilter
    {
        private int houghW;
        private int houghH;
        private UnsafeBitmap bmpHough;
        private int[,] houghMap;
        private int maxHough;

        /// <summary>
        /// Initializes a new instance of the <see cref="HoughTransform2"/> class.
        /// </summary>
        public HoughTransform2()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="HoughTransform2"/> class.
        /// </summary>
        /// <param name="_houghTransform">The _hough transform.</param>
        internal HoughTransform2(HoughTransform2 _houghTransform)
        {
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_bitmap"></param>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            bmpHough = _bitmap;
            maxHough = 0;
            houghH = 180;
            houghW = (int)Math.Sqrt(bmpHough.Width * bmpHough.Width + bmpHough.Height * bmpHough.Height) + 1;
            bmpHough = (UnsafeBitmap)_bitmap.Clone();
            //houghMap = new int[180, 180];// 180×180
            //houghMap = new int[bmp.Height,bmp.Width];
            houghMap = new int[houghH, houghW];//

            Rectangle rect = new Rectangle(0, 0, bmpHough.Width, bmpHough.Height);//
            BitmapData bmpData = bmpHough.BitmapData; //bmpHough.LockBits(rect, ImageLockMode.ReadWrite, bmpHough.PixelFormat);
            unsafe
            {
                byte* bp = (byte*)bmpData.Scan0.ToPointer();
                //IntPtr ptr = bmpData.Scan0;
                //int bytes = bmpHough.Width * bmpHough.Height;//
                //byte[] grayValues = new byte[bytes];
                //System.Runtime.InteropServices.Marshal.Copy(ptr, grayValues, 0, bytes);
                //int dataStrid = bmpData.Stride;

                Array.Clear(houghMap, 0, houghMap.Length);//
                int iMaxAngleNumber = 180;
                double dDist;
                int iDist;
                int n = 0;
                int k = 0;
                for (int i = 0; i < bmpHough.Height; i++)
                {
                    Console.WriteLine();
                    for (int j = 0; j < bmpHough.Width; j++)
                    {
                        //Console.Write(bp[i * bmpData.Stride + j] + "\t");
                        if (bp[i * bmpData.Stride + j] == 0)
                        {
                            n++;
                            for (int thet = 0; thet < 180; thet++)
                            {
                                double arc = thet * Math.PI / 180;
                                //p=x*Math.Cos(theta)+y*Math.Sin(theta);
                            //    //j=179,arc=0,i=0，rho 180，houghMap
                                int rho = Convert.ToInt16((j * Math.Cos(arc) + i * Math.Sin(arc)) / 8) + 90;  //int rho = (int)Math.Abs(((j * Math.Cos(arc) + i * Math.Sin(arc)) / 8) + 90); 
                                houghMap[thet, rho]++;
                                if (maxHough < houghMap[thet, rho])
                                    maxHough = houghMap[thet, rho];
                            }
                            //
                            for (int iAngleNumber = 0; iAngleNumber < iMaxAngleNumber; iAngleNumber++)
                            {
                                /*1
                                iDist = (int)Math.Abs(j * Math.Cos(iAngleNumber) +
                                    i * Math.Sin(iAngleNumber));
                                 */
                                k++;
                                dDist = (j * Math.Cos(iAngleNumber * Math.PI / 180.0) +
                                    i * Math.Sin(iAngleNumber * Math.PI / 180.0));      //sin(3.14)=0.0015926529,cos(3.14)=-0.99999873


                                /*3
                                double arc = iAngleNumber * Math.PI / 180;
                                iDist = Math.Abs(Convert.ToInt16((j * Math.Cos(arc) + i * Math.Sin(arc)) / 8) + 90);
                                 */
                                //1
                                if (dDist < 0) continue;
                                //iDist=(int)dDist;
                                iDist = Convert.ToInt16(dDist);
                                houghMap[iAngleNumber, iDist]++;
                                if (iDist!=dDist)
                                houghMap[iAngleNumber, iDist+1]++;
                                if (maxHough < houghMap[iAngleNumber, iDist])
                                    maxHough = houghMap[iAngleNumber, iDist];
                                iDist = (int)Math.Abs(i * Math.Cos(iAngleNumber  * Math.PI / 180.0) +
                                    j * Math.Sin(iAngleNumber  * Math.PI / 180.0));  

                                houghMap[iAngleNumber, iDist]++;
                                if (maxHough < houghMap[iAngleNumber, iDist])
                                {
                                    maxHough = houghMap[iAngleNumber, iDist];
                                }
                            }
                        }
                    }
                }
            }
            bmpHough.Dispose(); //bmpHough.UnlockBits(bmpData);
            return _bitmap;
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new HoughTransform2(this);
        }
    }
}
